package com.yue92.datalife.helper;

import com.yue92.datalife.common.CodeEnum;
import com.yue92.datalife.common.CommonUtil;
import com.yue92.datalife.exception.UncheckedException;
import com.yue92.datalife.model.Record;
import com.yue92.datalife.model.RecordItem;
import com.yue92.datalife.model.User;
import com.yue92.datalife.response.*;
import com.yue92.datalife.service.IRecordItemService;
import com.yue92.datalife.service.IRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @author mundo.wang on 2020/9/8
 */
@Component
public class RecordHelper {

    @Autowired
    private IRecordService recordService;

    @Autowired
    private IRecordItemService recordItemService;

    public RecordIndexRes index(User user) {

        List<Record> records = recordService.findByUserId(user.getId());

        List<RecordRes> list = new ArrayList<>();

        for (Record record : records) {
            list.add(RecordRes.builder()
                    .id(record.getId())
                    .name(record.getName())
                    .comment(record.getComment())
                    .allowCumulate(record.getAllowCumulate())
                    .sort(record.getSort()).build());
        }

        return RecordIndexRes.builder().list(list).build();
    }

    public Record checkAndGetRecord(Long recordId, User user) {
        Optional<Record> recordOptional = recordService.get(recordId);
        if (!recordOptional.isPresent()) {
            throw new UncheckedException(CodeEnum.FAILURE, "record not exist");
        }
        if (!recordOptional.get().getUserId().equals(user.getId())) {
            throw new UncheckedException(CodeEnum.FAILURE, "record forbid");
        }

        return recordOptional.get();
    }

    public RecordItem checkAndGetRecordItem(Long recordItemId, User user) {
        Optional<RecordItem> recordItemOptional = recordItemService.get(recordItemId);
        if (!recordItemOptional.isPresent()) {
            throw new UncheckedException(CodeEnum.FAILURE, "recordItem not exist");
        }
        Optional<Record> recordOptional = recordService.get(recordItemOptional.get().getRecordId());
        if (!recordOptional.isPresent()) {
            throw new UncheckedException(CodeEnum.FAILURE, "record not exist");
        }
        if (!recordOptional.get().getUserId().equals(user.getId())) {
            throw new UncheckedException(CodeEnum.FAILURE, "record forbid");
        }

        return recordItemOptional.get();
    }

    public RecordWeekRes week(Record record, LocalDate date) {

        LocalDate snapshotDate = date;

        int emptyTo = CommonUtil.getDayIndex(date.getDayOfWeek());
        date = date.minusDays(emptyTo);

        List<RecordItemDayRes> data = new ArrayList<>();
        do {
            List<RecordItem> list = recordItemService.getAllByRecordIdAndRecordDate(record.getId(), date);
            Integer sum = recordItemService.sum(record.getId(), date);

            List<RecordItemRes> items = new ArrayList<>();
            for (RecordItem recordItem : list) {
                items.add(RecordItemRes.builder()
                        .id(recordItem.getId())
                        .value(recordItem.getValue())
                        .comment(recordItem.getComment())
                        .build()
                );
            }

            data.add(RecordItemDayRes.builder()
                    .day(date.getDayOfMonth())
                    .date(date.toString())
                    .items(items)
                    .sum(sum)
                    .build()
            );
            date = date.plusDays(1L);
        } while (!date.getDayOfWeek().equals(DayOfWeek.SUNDAY));


        return RecordWeekRes.builder().
                list(data).recordDate(snapshotDate.toString())
                .dayIndex(emptyTo)
                .record(RecordRes.builder()
                        .id(record.getId())
                        .name(record.getName())
                        .build())
                .build();
    }

    public RecordMonthRes month(Record record, LocalDate date) {

        LocalDate currentDate = LocalDate.of(date.getYear(), date.getMonth(), 1);
        LocalDate endDate = LocalDate.of(date.getYear(), date.getMonth(), date.getMonth().length(date.isLeapYear()));

        int emptyTo = currentDate.getDayOfWeek().getValue();

        List<RecordItemDayRes> week = new ArrayList<>();
        while (emptyTo > 0 && emptyTo != DayOfWeek.SUNDAY.getValue()) {
            week.add(RecordItemDayRes.builder().build());

            emptyTo--;
        }

        List<List<RecordItemDayRes>> month = new ArrayList<>();
        int weekIndex = 0;

        while (true) {
            if (date.equals(currentDate)) {
                weekIndex = month.size();
            }

            List<RecordItem> list = recordItemService.getAllByRecordIdAndRecordDate(record.getId(), currentDate);
            Integer sum = recordItemService.sum(record.getId(), currentDate);

            List<RecordItemRes> items = new ArrayList<>();
            for (RecordItem recordItem : list) {
                items.add(RecordItemRes.builder()
                        .id(recordItem.getId())
                        .value(recordItem.getValue())
                        .comment(recordItem.getComment())
                        .build()
                );
            }

            week.add(RecordItemDayRes.builder()
                    .day(currentDate.getDayOfMonth())
                    .date(currentDate.toString())
                    .items(items)
                    .sum(sum)
                    .build()
            );

            if (currentDate.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
                month.add(week);

                week = new ArrayList<>();
            }

            if (currentDate.equals(endDate)) {
                if (week.size() > 0) {
                    int length = 7 - week.size();
                    if (length > 0) {
                        do {
                            week.add(RecordItemDayRes.builder().build());
                            length--;
                        } while (length > 0);
                    }

                    month.add(week);
                }

                break;
            }

            currentDate = currentDate.plusDays(1L);
        }

        return RecordMonthRes.builder()
                .list(month)
                .recordDate(date.toString())
                .record(RecordRes.builder()
                        .id(record.getId())
                        .name(record.getName())
                        .build())
                .dayIndex(CommonUtil.getDayIndex(date.getDayOfWeek()))
                .weekIndex(weekIndex)
                .build();
    }

}
